using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.Reflection;
using System.IO;
using System.Windows.Forms;
using NetMatters;

/******
 *
    Copyright 2008 Mitch Barnett
	This file is part of Global System Builder.

    Global System Builder is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Global System Builder is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Global System Builder.  If not, see <http://www.gnu.org/licenses/>.
 *
******/

namespace GSBService
{
    [ServiceContract(Namespace = "http://GSBService")]
    public interface IGSBService
    {
        [OperationContract(IsOneWay = false)]
        String CallIPCmd(string str);

        [OperationContract(IsOneWay = true)]
        void CallIPExecuteFile(string str);

        [OperationContract(IsOneWay = false)]
        ArrayList ListAssemblies();

        [OperationContract(IsOneWay = false)]
        Dictionary<string,ArrayList> ListTypes(string assemblyname);

        [OperationContract(IsOneWay = false)]
        Dictionary<string, ArrayList> ListMembers(string typename);
    }

    //required as the IP engine is running on a different thread
    [ServiceBehavior(UseSynchronizationContext = true)]


    public class GSBService : IGSBService
    {
        public static string gblAssemblyName;

        public string CallIPCmd(string str)
        {

            string cmd = GSBServiceForm.IPTextBox.ExecuteIPCommand(str);
            return cmd;
        }

        public void CallIPExecuteFile(string ipyfile)
        {
            //TODO: this is just a hack to make it work
            
            //Create Temp file and overwrite on each call - ok rude kack just to make work :-)
            StreamWriter sw = File.CreateText("C:\\projects\\gsbservice\\test.py");

            //Write the string
            sw.Write(ipyfile);

            //Close the file
            sw.Close();
            
            sw.Dispose();

            GSBServiceForm.IPTextBox.DoIPExecuteFile("C:\\projects\\gsbservice\\test.py");
          
        }

        public ArrayList ListAssemblies()
        {
            ArrayList assemblyNameArray = new ArrayList();

            ICollection keyColl = GSBServiceForm.gsbGlobalAssemblyHashtable.Keys;

            foreach (string assemblyName in keyColl)
            {
                assemblyNameArray.Add(assemblyName);
            }

            return assemblyNameArray;
        }

        public Dictionary<string, ArrayList> ListTypes(string assemblyname)
        {
            Dictionary<string, ArrayList> typeDict = new Dictionary<string, ArrayList>();

            ArrayList classArray = new ArrayList();
            ArrayList enumArray = new ArrayList();
            ArrayList interfaceArray = new ArrayList();
            //TODO: add another array for each other type of interest

            gblAssemblyName = assemblyname;

            Assembly aAssembly = (Assembly)GSBServiceForm.gsbGlobalAssemblyHashtable[assemblyname];

            Type[] types = aAssembly.GetTypes();

            foreach (Type type in types)
            {
                if (type.IsPublic)
                {
                    string atypename = splitTypeName(type.ToString());

                    if (type.IsClass)
                    {  
                        classArray.Add(atypename);
                    }

                    if (type.IsEnum)
                    {
                        enumArray.Add(atypename);
                    }

                    if (type.IsInterface)
                    {
                        interfaceArray.Add(atypename);
                    }

                    //if (type.IsValueType) and any other type we need to capture here
                    //{

                    //}
                }

            }

            typeDict.Add("class",classArray);
            typeDict.Add("enum", enumArray);
            typeDict.Add("interface", interfaceArray);

            return typeDict;

        }

        public Dictionary<string, ArrayList> ListMembers(string typename)
        {
            Dictionary<string, ArrayList> memberDict = new Dictionary<string, ArrayList>();

            Assembly aAssembly = (Assembly)GSBServiceForm.gsbGlobalAssemblyHashtable[gblAssemblyName];

            //TODO: check t is not null try/catch exceptions
            Type t = aAssembly.GetType(aAssembly.GetName().Name + "." + typename);

            // Static fields.
            FieldInfo[] fi = t.GetFields(BindingFlags.Static | BindingFlags.Public);
            ArrayList sf = new ArrayList();
            foreach (MemberInfo m in fi)
            {
                sf.Add(m.Name);
            }
            memberDict.Add("staticfields", sf);


            // Static properties.
            PropertyInfo[] pi = t.GetProperties(BindingFlags.Static | BindingFlags.Public);
            ArrayList sp = new ArrayList();
            foreach (MemberInfo m in pi)
            {
                sp.Add(m.Name);
            }
            memberDict.Add("staticproperties", sp);

            // Static events.
            EventInfo[] ei = t.GetEvents(BindingFlags.Static | BindingFlags.Public);
            ArrayList se = new ArrayList();
            foreach (MemberInfo m in pi)
            {
                se.Add(m.Name);
            }
            memberDict.Add("staticevents", se);

            // Static methods.
            MethodInfo[] mi = t.GetMethods(BindingFlags.Static | BindingFlags.Public);
            ArrayList sm = new ArrayList();
            foreach (MemberInfo m in mi)
            {
                sm.Add(m.Name);
            }
            memberDict.Add("staticmethods", sm);


            // Constructors.
            ConstructorInfo[] ci = t.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
            ArrayList cs = new ArrayList();
            foreach (MemberInfo m in ci)
            {
                cs.Add(m.Name);
            }
            memberDict.Add("constructors", cs);


            // Instance fields.
            fi = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
            ArrayList insf = new ArrayList();
            foreach (MemberInfo m in fi)
            {
                insf.Add(m.Name);
            }
            memberDict.Add("instancefields", insf);


            // Instance properties.
            pi = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            ArrayList ip = new ArrayList();
            foreach (MemberInfo m in pi)
            {
                ip.Add(m.Name);
            }
            memberDict.Add("instanceproperties", ip);

            // Instance events.
            ei = t.GetEvents(BindingFlags.Instance | BindingFlags.Public);
            ArrayList ie = new ArrayList();
            foreach (MemberInfo m in ei)
            {
                ie.Add(m.Name);
            }
            memberDict.Add("instanceevents", ie);

            // Instance methods.
            mi = t.GetMethods(BindingFlags.Instance | BindingFlags.Public);
            ArrayList im = new ArrayList();
            foreach (MemberInfo m in mi)
            {
                im.Add(m.Name);
            }
            memberDict.Add("instancemethods", im);

            return memberDict;
    }


        private string splitTypeName(string s)
        {
            char[] delimiterChars = { '.', ' ', '\t' };
            string text = s;
            string[] words = text.Split(delimiterChars);
            int myLength = words.Length;
            return words.GetValue(myLength - 1).ToString();

        }

    }
}
